home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Technology Seed / ADC Seed CD - July 1999.toast / USB / Mac OS USB DDK v1.2 / Examples / USBSampleStorageDriver / SampleStorageDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-15  |  38.5 KB  |  1,147 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SampleStorageDriver.c
  3.  
  4.     Contains:    All functions for the Class driverto access and control the device
  5.  
  6.     Version:        1.1
  7.  
  8.     Copyright:    © 1998-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  14.     includes
  15.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  16. #include <Devices.h>
  17. #include <DriverServices.h>
  18. #include <Interrupts.h>
  19. #include <LowMem.h>
  20. #include <Folders.h>
  21. #include <MacTypes.h>
  22. #include <CodeFragments.h>
  23.  
  24. #include <USB.h>
  25.  
  26. #include "SampleStorageDriverAPI.h"
  27. #include "SampleStorageDeviceID.h"
  28. #include "SampleStorageDriver.h"
  29.  
  30. extern TheStorageClassDispatchTable;
  31.  
  32. enum
  33. {
  34.     kCString = 0,                // StateStr, USBStatusStr selector
  35.     kPString                        // StateStr, USBStatusStr selector
  36. };
  37.  
  38. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  39.     globals
  40.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  41. static             Boolean                            gBeenThereDoneThat = false;    // Flag indicating if this driver has been called before
  42.  
  43. static            Boolean                            gConfigured = false;                // No calls to dispatch table until this is true.
  44.  
  45. static            UInt32                            gConfigureStatus;                    // Current state of cinfiguration
  46.  
  47. static            Boolean                            gOKToRemoval = true;            // Used in StorageClassDriverNotifyProc to prevent removal by expert
  48.  
  49. static struct    StorageClassInfo                gStorageClassInfo;                // Holds all of the common items
  50.     
  51. static struct    StorageClassTransactionPB    gInterruptPB;                        // Used only for the interrupt pipe
  52.  
  53. static struct    StorageClassStatusPB            gGetStatusPB;                        // Used only for the USB Get Status request
  54.  
  55. static struct    StorageClassControlPB        gControlPB;                            // Used only for aborting a R/W transaction
  56.  
  57. static struct    StorageClassTransactionPB    gCommandPB;                            // Used only by StorageClassDriverExecuteCommand
  58.  
  59. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  60.     prototypes
  61.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  62.  
  63. static void InitParamBlock(USBDeviceRef theDeviceRef, USBPB* paramblock);
  64.  
  65. static Boolean    ImmediateError(OSStatus err);
  66.  
  67. static void    StorageDeviceConfigureCompletion(USBPB* pb);
  68.  
  69. static void    StorageDeviceInitiateConfiguration(USBPB* pb);
  70.  
  71. static OSStatus StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr );
  72.  
  73. static OSStatus StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr );
  74.  
  75. // Completion routines
  76.  
  77. static void ReadBlockCompletion(USBPB* usbPB);
  78.  
  79. static void WriteBlockCompletion(USBPB* usbPB);
  80.  
  81. static void ExecuteCommandCompletion(USBPB* usbPB);
  82.  
  83. static void ExecuteBufferedCommandCompletion(USBPB* usbPB);
  84.  
  85. static void GetStatusCompletion(USBPB* usbPB);
  86.  
  87. static void AbortTransactionCompletion(USBPB* usbPB);
  88.  
  89. //****************************************************************************************************
  90.  
  91. #if DEBUG
  92.  
  93. static void
  94. HexStr(    unsigned long    v,
  95.             unsigned char    *p )
  96. {
  97.     int    shift;
  98.     
  99.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  100.     {
  101.         char c = (v >> shift) & 0x0F;
  102.         *p++ = c + (c > 9? ('A'-10): '0');
  103.     }
  104. }
  105.  
  106. static unsigned char *
  107. USBStatusStr(    OSStatus    usbStatus,
  108.                     int        kind )
  109. {
  110.     unsigned char *p;
  111.  
  112.     switch ( usbStatus )
  113.     {
  114.         case    kUSBInternalErr:                    p = "\p" kStrStorageClass "Internal error"; break;
  115.         case    kUSBUnknownDeviceErr:            p = "\p" kStrStorageClass "Unknown device"; break;
  116.         case    kUSBUnknownPipeErr:                 p = "\p" kStrStorageClass "Unknown pipe"; break;
  117.         case    kUSBTooManyPipesErr:                p = "\p" kStrStorageClass "Too many pipes"; break;
  118.         case    kUSBIncorrectTypeErr:            p = "\p" kStrStorageClass "Incorrect type"; break;
  119.         case    kUSBRqErr:                            p = "\p" kStrStorageClass "Request error"; break;
  120.         case    kUSBUnknownRequestErr:            p = "\p" kStrStorageClass "Unknown request"; break;
  121.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrStorageClass "Too many transactions"; break;
  122.         case    kUSBAlreadyOpenErr:                p = "\p" kStrStorageClass "Already open"; break;
  123.         case    kUSBNoDeviceErr:                    p = "\p" kStrStorageClass "No device"; break;
  124.         case    kUSBDeviceErr:                        p = "\p" kStrStorageClass "Device error"; break;
  125.         case    kUSBOutOfMemoryErr:                p = "\p" kStrStorageClass "Out of memory"; break;
  126.         case    kUSBNotFound:                        p = "\p" kStrStorageClass "USB Not found"; break;
  127.         case    kUSBLinkErr:                        p = "\p" kStrStorageClass "Link Err"; break;
  128.         case    kUSBCRCErr:                            p = "\p" kStrStorageClass "Comms/Device err, bad CRC";  break;        
  129.         case    kUSBBitstufErr:                    p = "\p" kStrStorageClass "Comms/Device err, bitstuffing"; break;        
  130.         case    kUSBDataToggleErr:                p = "\p" kStrStorageClass "Comms/Device err, Bad data toggle"; break;        
  131.         case    kUSBEndpointStallErr:            p = "\p" kStrStorageClass "Device didn't understand"; break;        
  132.         case    kUSBNotRespondingErr:            p = "\p" kStrStorageClass "No device, device hung"; break;        
  133.         case    kUSBPIDCheckErr:                    p = "\p" kStrStorageClass "Comms/Device err, PID CRC error"; break;        
  134.         case    kUSBWrongPIDErr:                    p = "\p" kStrStorageClass "Comms/Device err, Bad or wrong PID"; break;        
  135.         case    kUSBOverRunErr:                    p = "\p" kStrStorageClass "Packet too large or more data than buffer"; break;        
  136.         case    kUSBUnderRunErr:                    p = "\p" kStrStorageClass "Less data than buffer"; break;        
  137.         case    kUSBRes1Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  138.         case    kUSBRes2Err:                        p = "\p" kStrStorageClass "kUSBRes1Err"; break;        
  139.         case    kUSBBufOvrRunErr:                    p = "\p" kStrStorageClass "Buffer over run error"; break;        
  140.         case    kUSBBufUnderRunErr:                p = "\p" kStrStorageClass "Buffer under run error"; break;        
  141.         case    kUSBNotSent1Err:                    p = "\p" kStrStorageClass "Transaction not sent1"; break;        
  142.         case    kUSBNotSent2Err:                    p = "\p" kStrStorageClass "Transaction not sent2"; break;    
  143.         default:
  144.             p = "\p" kStrStorageClass "Unknown error nnnnnnnn";
  145.             HexStr( usbStatus, p + *p - 8 + 1 );
  146.             break;
  147.     }
  148.     
  149.     return kind == kPString? p: p + 1;
  150. }
  151.  
  152.  
  153. static unsigned char*
  154. StateStr(    OSStatus    refCon,
  155.                 int        kind )
  156. {
  157.     unsigned char *p;
  158.  
  159.     refCon &= ~(kCompletionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  160.     switch ( refCon )
  161.     {        
  162.         case kSetConfig:                                    p = kStrStorageClass "kSetConfig"; break;
  163.         case kGetFullConfiguration:                    p = kStrStorageClass "kGetFullConfiguration"; break;
  164.         case kFindStorageInterface:                    p = kStrStorageClass "kFindStorageInterface"; break;
  165.         case kStorageConfigureInterface:                p = kStrStorageClass "kStorageConfigureInterface"; break;
  166.         
  167.         case kNewInterfaceRef:                            p = kStrStorageClass "kNewInterfaceRef"; break;
  168.         case kStorageFindInterruptPipe:                p = kStrStorageClass "kStorageFindInterruptPipe"; break;
  169.         case kStorageFindBulkInPipe:                    p = kStrStorageClass "kStorageFindBulkInPipe"; break;
  170.         case kStorageFindBulkOutPipe:                    p = kStrStorageClass "kStorageFindBulkOutPipe"; break;
  171.                 
  172.         case kStorageReadInterrupt:                    p = kStrStorageClass "kStorageReadInterrupt"; break;
  173.         
  174.         case kStorageExecuteCommand:                    p = kStrStorageClass "kStorageExecuteCommand"; break;
  175.         case kStorageExecuteCommandCompletion:        p = kStrStorageClass "kStorageExecuteCommandCompletion"; break;
  176.         case kStorageBulkIOComplete:                    p = kStrStorageClass "kStorageBulkIOComplete"; break;
  177.         case kStorageGetStatus:                            p = kStrStorageClass "kStorageGetStatus"; break;
  178.         case kStorageGetStatusBulkRead:                p = kStrStorageClass "kStorageGetStatusBulkRead"; break;
  179.         
  180.         default:
  181.             p = "\pUnknown state nnnnnnnn";
  182.             HexStr( refCon, p + *p - 8 + 1 );
  183.             break;
  184.     }
  185.     return kind == kPString? p: p + 1;    
  186. }
  187. #endif
  188.  
  189. static unsigned char
  190. HiHex( int v )
  191. {
  192.     unsigned char    hinibble = (v >> 4) & 0x0f;
  193.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  194. }
  195.  
  196.  
  197. static unsigned char
  198. LoHex( int v )
  199. {
  200.     unsigned char    lonibble = v & 0x0f;
  201.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  202. }
  203.  
  204.  
  205. static void
  206. InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  207. {
  208.     paramblock->usbReference =    theDeviceRef;
  209.     paramblock->pbVersion =        kUSBCurrentPBVersion;
  210.     paramblock->pbLength =        sizeof(USBPB);
  211.     paramblock->usb.cntl.WIndex =        0;             
  212.     paramblock->usbBuffer =        nil;        
  213.     paramblock->usbStatus =        noErr;
  214.     paramblock->usbReqCount =    0;
  215.     paramblock->usb.cntl.WValue =        0;
  216.     paramblock->usbFlags =        0;
  217. }
  218.  
  219.  
  220. static Boolean
  221. ImmediateError(OSStatus err)
  222. {
  223.     return((err != kUSBPending) && (err != noErr) );
  224. }
  225.  
  226.  
  227. OSStatus
  228. GetUSBVersion(UInt32* usbVersion)
  229. {
  230. OSStatus result;
  231.  
  232.     result = Gestalt('usbv', usbVersion);
  233.     
  234.     return result;
  235. }
  236.  
  237.  
  238. OSErr
  239. GetInterfaceDescriptor(    LogicalAddress pConfigDesc,
  240.                                 UInt32 ReqInterface,
  241.                                 USBInterfaceDescriptorPtr * hInterfaceDesc)
  242. {
  243. UInt32                            totalLength;
  244. void *                            pEndOfDescriptors;
  245. USBInterfaceDescriptorPtr    pMyIntDesc;
  246. USBDescriptorHeaderPtr        pCurrentDesc;
  247. UInt32                            anAddress,
  248.                                     anOffset;
  249.  
  250.     totalLength =            ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength;
  251.     pEndOfDescriptors =    (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  252.     pCurrentDesc =            (USBDescriptorHeaderPtr)pConfigDesc;        // point the currentdesc to the start of the config space
  253.     
  254.     while (pCurrentDesc < pEndOfDescriptors)                                // as long as we haven't exhausted all the descriptors
  255.     {
  256.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)        // look at the current descriptor
  257.         {
  258.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;        // if it's an interface descriptor
  259.             if (pMyIntDesc->interfaceNumber == ReqInterface)            // see if it's the request descriptor
  260.             {
  261.                 *hInterfaceDesc = pMyIntDesc;                                    // if it is, then return with hInterfaceDesc set to the
  262.                 return kUSBNoErr;                                                    // current descriptor pointer
  263.             }
  264.         }
  265.         anAddress =        (unsigned long) pCurrentDesc;                        // Nope, that either wasn't an interface descriptor
  266.         anOffset  =        (unsigned long) pCurrentDesc->length;
  267.         anAddress +=    anOffset;
  268.         pCurrentDesc =    (USBDescriptorHeaderPtr) anAddress;
  269.     }                                                                                    // or it was, but not the droid we're looking for.
  270.     return -1;
  271. }
  272.  
  273. //****************************************************************************************************
  274. //
  275. //        StorageClassDriverAPI.c calls end up here...
  276. //
  277. //****************************************************************************************************
  278.  
  279. OSStatus
  280. StorageClassDriverInitialize(void)
  281. {
  282.     return noErr;
  283. }
  284.  
  285.  
  286. OSStatus
  287. StorageClassDriverControl(    UInt32    theControlSelector,
  288.                                     void        *theControlData)
  289. {
  290. #pragma unused (theControlData)
  291.  
  292. OSStatus        status;
  293.  
  294.     switch (theControlSelector)
  295.     {
  296.         case kControlDisableRemoval:
  297.             gOKToRemoval = false;
  298.             status = noErr;
  299.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlDisableRemoval", 0) );
  300.             break;
  301.             
  302.         case kControlEnableRemoval:
  303.             gOKToRemoval = true;
  304.             status = noErr;
  305.             IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver: kControlEnableRemoval", 0) );
  306.             break;
  307.         
  308.         default:
  309.             status = controlErr;
  310.             break;
  311.     }    
  312.     return status;
  313. }
  314.  
  315.  
  316. OSStatus
  317. StorageClassDriverStatus(    UInt32    theInfoSelector,
  318.                                     void        *theInfo)
  319. {
  320. OSStatus        status;
  321.  
  322.     switch (theInfoSelector)
  323.     {
  324.         case kStatusConfiguration:                        // Return the current confifuration status
  325.             *((UInt32*) theInfo) = gConfigureStatus;
  326.             status = noErr;
  327.             break;
  328.             
  329.         case kStatusDeviceStatus:
  330.             status = StorageClassDriverGetStatus( (StorageStatusPBPtr) theInfo );
  331.             break;
  332.         
  333.         case kStatusRemovalStatus:
  334.             *((Boolean*) theInfo) = gOKToRemoval;
  335.             status = noErr;
  336.             break;
  337.             
  338.         default:
  339.             status = statusErr;
  340.             break;
  341.     }    
  342.     return status;
  343. }
  344.  
  345.  
  346. // All device requests come through here
  347. OSStatus
  348. StorageClassDriverExecuteCommand( StorageExecuteCommandPBPtr cmdPBPtr )
  349. {
  350. OSStatus            myErr;
  351. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverExecuteCommand", 0) );
  352.  
  353.     // Make sure we have been able to configure the device
  354.     if (gConfigured == false)
  355.     {
  356.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  357.         return kClassNotConfiguredErr;
  358.     }
  359.         
  360.     // check if we already have a read in progress, if so return error.
  361.     if (gCommandPB.busy == true)
  362.     {
  363.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand busy", 0) );
  364.         return kCommandBusyError;
  365.     }
  366.     
  367.     cmdPBPtr->status = kRequestPending;
  368.  
  369.     BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  370.         
  371.     gCommandPB.busy = true;
  372.  
  373.     InitParamBlock(gStorageClassInfo.interfaceRef, &gCommandPB.usbPB);
  374.     
  375.     // Get a local copy of the callers cdb
  376.     BlockCopy(&cmdPBPtr->cdb[0], &gCommandPB.cdb[0], kCDBSize);
  377.     
  378.     gCommandPB.flags = cmdPBPtr->flags;
  379.     
  380.     gCommandPB.userPBPtr = (StorageExecuteCommandPBPtr) cmdPBPtr;                // Save the ptr to the callers PB
  381.     
  382.     gCommandPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  383.     
  384.     gCommandPB.usbPB.usb.cntl.BRequest =        0;
  385.     gCommandPB.usbPB.usb.cntl.WValue =            0;
  386.     gCommandPB.usbPB.usb.cntl.WIndex =            0;
  387.     
  388.     gCommandPB.usbPB.usbBuffer =            (Ptr)&gCommandPB.cdb[0];
  389.     gCommandPB.usbPB.usbReqCount =        kCDBSize;
  390.     gCommandPB.usbPB.usbFlags =            0;
  391.         
  392.     gCommandPB.usbPB.usbRefcon =            kStorageExecuteCommand;
  393.     
  394.     gCommandPB.usbPB.usbCompletion =        (USBCompletion)ExecuteCommandCompletion;                // Don't use double buffering for builk I/O
  395.         
  396.     myErr = USBDeviceRequest(&gCommandPB.usbPB);
  397.             
  398.     return myErr;
  399. }
  400.  
  401. static void ExecuteCommandCompletion(USBPB* usbPB)
  402. {
  403. OSStatus                            myErr;
  404. StorageExecuteCommandPBPtr    cmdPBPtr;
  405.  
  406.     // Retrieve the callers pb
  407.     cmdPBPtr = (StorageExecuteCommandPBPtr) gCommandPB.userPBPtr;
  408.         
  409. //    IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 5 ) );
  410.  
  411.     switch(usbPB->usbRefcon)
  412.     {
  413.         case kStorageExecuteCommand:        // Device request completion
  414.             // First check to see if an error occurred on the command out
  415.             if (usbPB->usbStatus != noErr)
  416.             {
  417.                 // Clear stalled control pipe
  418.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageExecuteCommand error. usbStatus:" , usbPB->usbStatus ) );
  419.                 USBClearPipeStallByReference(usbPB->usbReference);
  420.                 cmdPBPtr->status = usbPB->usbStatus;
  421.                                 
  422.                 gCommandPB.busy = false;
  423.                 if(cmdPBPtr->completionProc != nil)
  424.                 {
  425.                     (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  426.                 }
  427.                 break;
  428.             }
  429.             
  430.             // If there is to be no data transfer then we are done and can return to the caller
  431.             if (gCommandPB.flags & kStorageNoData)
  432.             {
  433.                 cmdPBPtr->status = usbPB->usbStatus;
  434.                                 
  435.                 gCommandPB.busy = false;
  436.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  437.                 
  438.                 break;
  439.             }
  440.             // Setup the usb pb for either bulk in or out
  441.             if (gCommandPB.flags & kStorageDataIn)
  442.                 InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  443.             else if (gCommandPB.flags & kStorageDataOut)
  444.                 InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  445.                             
  446.             // Check to see if the amount of data to be transferred is greater
  447.             // than kUSBMaxBulkTransfer.  This is to get around an issue with
  448.             // the USB Manager/USL where the amount of data transferred per
  449.             // Bulk Request needs to be limited to a specific amount
  450.             if ( cmdPBPtr->expectedCount > kUSBMaxBulkTransfer )
  451.             {
  452.                 usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  453.             }
  454.             else
  455.             {
  456.                 usbPB->usbReqCount     = cmdPBPtr->expectedCount;
  457.             }
  458.             
  459.             usbPB->usbRefcon =        kStorageBulkIOComplete;
  460.             usbPB->usbActCount =        0;
  461.             usbPB->usbBuffer =        cmdPBPtr->userBuffer;
  462.             usbPB->usbCompletion =    (USBCompletion)ExecuteCommandCompletion;
  463.             
  464.             // Start a bulk in or out transaction
  465.             if (gCommandPB.flags & kStorageDataIn)
  466.                 myErr = USBBulkRead(&gCommandPB.usbPB);
  467.             else if (gCommandPB.flags & kStorageDataOut)
  468.                 myErr = USBBulkWrite(&gCommandPB.usbPB);
  469.             
  470.             if    (ImmediateError(myErr))
  471.             {
  472.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr) );
  473.                 cmdPBPtr->actualCount =    usbPB->usbActCount;
  474.                 cmdPBPtr->status = myErr;
  475.                 gCommandPB.busy = false;
  476.                 (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  477.             }
  478.             break;
  479.         
  480.         case kStorageBulkIOComplete:
  481.         
  482.             cmdPBPtr->actualCount =    usbPB->usbActCount;                // Update the users byte count
  483.             cmdPBPtr->status =        usbPB->usbStatus;                    // and status
  484.             
  485.             if (usbPB->usbStatus != noErr)                                // Clear a possible pipe stall
  486.             {
  487.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageBulkIOComplete error. usbStatus:" , usbPB->usbStatus ) );
  488.                 USBClearPipeStallByReference(usbPB->usbReference);
  489.             }
  490.             else if ( cmdPBPtr->actualCount != cmdPBPtr->expectedCount)
  491.             {
  492.                 // If we have not yet transfered all the data and there are no Errors
  493.                 // Setup the usb pb for either bulk in or out
  494.                 if (gCommandPB.flags & kStorageDataIn)
  495.                 {
  496.                     InitParamBlock(gStorageClassInfo.readPipeRef, usbPB);
  497.                 }
  498.                 else if (gCommandPB.flags & kStorageDataOut)
  499.                 {
  500.                     InitParamBlock(gStorageClassInfo.writePipeRef, usbPB);
  501.                 }
  502.     
  503.                 if ( (cmdPBPtr->expectedCount - cmdPBPtr->actualCount) > kUSBMaxBulkTransfer )
  504.                 {
  505.                     usbPB->usbReqCount     = kUSBMaxBulkTransfer;
  506.                 }
  507.                 else
  508.                 {
  509.                     usbPB->usbReqCount     = (cmdPBPtr->expectedCount - cmdPBPtr->actualCount);
  510.                 }
  511.                 
  512.                 usbPB->usbRefcon         = kStorageBulkIOComplete;
  513.                 usbPB->usbActCount     = 0;
  514.                 usbPB->usbBuffer         = (cmdPBPtr->userBuffer) + (cmdPBPtr->actualCount);
  515.                 usbPB->usbCompletion = (USBCompletion)ExecuteCommandCompletion;
  516.                 
  517.                 // Continue a bulk in or out transaction
  518.                 if (gCommandPB.flags & kStorageDataIn)
  519.                 {
  520.                     myErr = USBBulkRead(&gCommandPB.usbPB);
  521.                 }
  522.                 else if (gCommandPB.flags & kStorageDataOut)
  523.                 {
  524.                     myErr = USBBulkWrite(&gCommandPB.usbPB);
  525.                 }
  526.                 
  527.                 if    (ImmediateError(myErr))
  528.                 {
  529.                     USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageExecuteCommand - immediate error", myErr);
  530.                     cmdPBPtr->status = myErr;
  531.                     gCommandPB.busy = false;
  532.                     if(cmdPBPtr->completionProc != nil)
  533.                     {
  534.                         (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  535.                     }
  536.                 }
  537.                 break;
  538.             }
  539.             
  540.             gCommandPB.busy = false;
  541.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  542.             break;
  543.             
  544.         default:
  545.             IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: ExecuteCommandCompletion - unknown state!", 5) );
  546.             cmdPBPtr->actualCount =    0;
  547.             cmdPBPtr->status = kUSBInternalErr;
  548.                         
  549.             gCommandPB.busy = false;
  550.             (*cmdPBPtr->completionProc)((StorageExecuteCommandPBPtr) cmdPBPtr);
  551.             break;
  552.     }
  553. }
  554.  
  555. OSStatus
  556. StorageClassDriverGetStatus( StorageStatusPBPtr statusPBPtr )
  557. {
  558. OSStatus    myErr;
  559.     
  560.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverGetStatus", 0) );
  561.  
  562.     // Make sure we have been able to configure the device
  563.     if (gConfigured == false)
  564.     {
  565.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverExecuteCommand not configured", 0) );
  566.         return kClassNotConfiguredErr;
  567.     }
  568.         
  569.     // check if we already have a status request in progress, if so return error.
  570.     if (gGetStatusPB.busy == true)
  571.     {
  572.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverGetStatus busy", 0) );
  573.         return kCommandBusyError;
  574.     }
  575.     
  576.     BlockZero(&gGetStatusPB, sizeof(StorageClassStatusPB));
  577.     
  578.     gGetStatusPB.busy = true;
  579.     
  580.     gGetStatusPB.userPBPtr = statusPBPtr;
  581.     
  582.     InitParamBlock(gStorageClassInfo.interfaceRef, &gGetStatusPB.usbPB);
  583.             
  584.     gGetStatusPB.usbPB.usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);            
  585.     
  586.     gGetStatusPB.usbPB.usb.cntl.BRequest =            kUSBRqGetStatus;
  587.     gGetStatusPB.usbPB.usb.cntl.WIndex =            0;
  588.     gGetStatusPB.usbPB.usb.cntl.WValue =            0;
  589.     
  590.     gGetStatusPB.usbPB.usbBuffer =            (Ptr)&gGetStatusPB.status[0];
  591.     gGetStatusPB.usbPB.usbReqCount =            kStatusSize;
  592.     gGetStatusPB.usbPB.usbFlags =                0;
  593.         
  594.     gGetStatusPB.usbPB.usbRefcon =            kStorageGetStatus;
  595.     gGetStatusPB.usbPB.usbCompletion =        (USBCompletion)GetStatusCompletion;
  596.             
  597.     myErr = USBDeviceRequest(&gGetStatusPB.usbPB);
  598.             
  599.     return myErr;
  600. }
  601.  
  602.  
  603.  
  604. static void GetStatusCompletion(USBPB* usbPB)
  605. {
  606. StorageStatusPBPtr    userPBPtr;
  607.     
  608.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 6 ) );
  609.     
  610.     // Retrieve the callers pb
  611.     userPBPtr = (StorageStatusPBPtr) gGetStatusPB.userPBPtr;
  612.         
  613.     userPBPtr->status =                usbPB->usbStatus;
  614.     userPBPtr->deviceStatus[0] =    gGetStatusPB.status[0];
  615.     userPBPtr->deviceStatus[1] =    gGetStatusPB.status[1];
  616.                     
  617.     gGetStatusPB.busy = false;
  618.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  619. }
  620.  
  621.  
  622. OSStatus
  623. StorageClassDriverAbortTransaction( StorageControlPBPtr controlPBPtr )
  624. {
  625. OSStatus            myErr;
  626.  
  627.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\p • StorageClassDriverAbortTransaction", 0) );
  628.  
  629.     // Make sure we have been able to configure the device
  630.     if (gConfigured == false)
  631.     {
  632.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction not configured", 0) );
  633.         return kClassNotConfiguredErr;
  634.     }
  635.         
  636.     // check if we already have a status request in progress, if so return error.
  637.     if (gControlPB.busy == true)
  638.     {
  639.         IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriver StorageClassDriverAbortTransaction busy", 0) );
  640.         return kCommandBusyError;
  641.     }
  642.     
  643.     BlockZero(&gControlPB, sizeof(StorageControlPB));
  644.     
  645.     gControlPB.busy = true;
  646.     
  647.     gControlPB.userPBPtr = controlPBPtr;
  648.     
  649.     InitParamBlock(gStorageClassInfo.interfaceRef, &gControlPB.usbPB);
  650.             
  651.     gControlPB.usbPB.usb.cntl.BMRequestType =    0x02;            // Clear feature        
  652.     
  653.     gControlPB.usbPB.usb.cntl.BRequest =        kUSBRqClearFeature;
  654.     
  655.     if (controlPBPtr->selector == 0)                        // Abort read pipe
  656.         gControlPB.usbPB.usb.cntl.WIndex =        0x82;
  657.     else                                                            // Abort write pipe
  658.         gControlPB.usbPB.usb.cntl.WIndex =        0x01;
  659.         
  660.     gControlPB.usbPB.usb.cntl.WValue =            0;                // 0 = clear endpoint stall
  661.     
  662.     gControlPB.usbPB.usbBuffer =            nil;
  663.     gControlPB.usbPB.usbReqCount =        0;
  664.     gControlPB.usbPB.usbFlags =            0;
  665.         
  666.     gControlPB.usbPB.usbRefcon =            kStorageGetStatus;
  667.     gControlPB.usbPB.usbCompletion =        (USBCompletion)AbortTransactionCompletion;
  668.             
  669.     myErr = USBDeviceRequest(&gControlPB.usbPB);
  670.             
  671.     return myErr;
  672. }
  673.  
  674.  
  675.  
  676. static void AbortTransactionCompletion(USBPB* usbPB)
  677. {
  678. StorageControlPBPtr    userPBPtr;
  679.     
  680.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 7 ) );
  681.     
  682.     // Retrieve the callers pb
  683.     userPBPtr = (StorageControlPBPtr) gControlPB.userPBPtr;
  684.         
  685.     userPBPtr->status =                usbPB->usbStatus;
  686.                     
  687.     gControlPB.busy = false;
  688.     (*userPBPtr->completionProc)((StorageExecuteCommandPBPtr) userPBPtr);
  689. }
  690.  
  691.  
  692. static void ReadInterruptCompletion(USBPB* usbPB)
  693. {
  694.     gStorageClassInfo.transDepth--;
  695.     
  696.     if (usbPB->usbStatus == kUSBEndpointStallErr)
  697.     {
  698.         USBClearPipeStallByReference(gStorageClassInfo.interruptPipeRef);
  699.     }
  700.     InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  701.  
  702.     usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  703.     usbPB->usbReqCount =        0x02;
  704.     usbPB->usbRefcon =        kStorageReadInterrupt;
  705.     usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  706.     
  707.     StorageDeviceInitiateConfiguration(usbPB);
  708. }
  709.  
  710. void
  711. StorageDeviceInitiateConfiguration(USBPB *usbPB)
  712. {
  713. OSStatus myErr;
  714. StorageClassTransactionPB*    pTransPB = (StorageClassTransactionPB*) usbPB;
  715.  
  716.     gStorageClassInfo.transDepth++;
  717.     
  718.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > kMaxTransitions))
  719.     {
  720.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Illegal Transaction Depth", usbPB->usbRefcon) );
  721.         gConfigureStatus = kConfigureFailed;
  722.     }
  723.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 2 ) );
  724.     
  725.     switch(usbPB->usbRefcon & ~kRetryTransaction)
  726.     {    
  727.         case kGetFullConfiguration:
  728.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  729.             
  730.             usbPB->usb.cntl.WIndex =            0;             // First try configuration 0, if it doesn't succeed, then try config 1
  731.             usbPB->usbRefcon |=        kCompletionPending;
  732.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  733.             
  734.             myErr = USBGetFullConfigurationDescriptor(usbPB);
  735.             if(ImmediateError(myErr))
  736.             {
  737.                 gConfigureStatus = kConfigureFailed;
  738.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration (#0) - immediate error", myErr) );
  739.             }
  740.             break;
  741.         
  742.         case kSetConfig:
  743.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  744.             
  745.             usbPB->usb.cntl.BMRequestType =    USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);
  746.             usbPB->usb.cntl.BRequest =            kUSBRqSetConfig;
  747.             usbPB->usb.cntl.WValue =            gStorageClassInfo.pFullConfigDescriptor->configValue;         // Use configuration ID value from descriptor
  748.             usbPB->usbRefcon |=             kCompletionPending;
  749.             
  750.             usbPB->usbCompletion =        (USBCompletion)StorageDeviceConfigureCompletion;
  751.             
  752.             myErr = USBDeviceRequest(usbPB);
  753.             if(ImmediateError(myErr))
  754.             {
  755.                 gConfigureStatus = kConfigureFailed;
  756.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kSetConfig - immediate error", myErr) );
  757.             }
  758.             break;
  759.         
  760.         case kFindStorageInterface:
  761.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  762.             usbPB->usbActCount =        0;
  763.  
  764.             usbPB->usbClassType =    kDriverClassID;
  765.             usbPB->usbSubclass =        kDriverSubClassID;
  766.             usbPB->usbProtocol =        0;
  767.             usbPB->usb.cntl.WValue =        0;
  768.             usbPB->usbRefcon |=        kCompletionPending;
  769.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  770.             
  771.             myErr = USBFindNextInterface(usbPB);
  772.             if(ImmediateError(myErr))
  773.             {
  774.                 gConfigureStatus = kConfigureFailed;
  775.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kFindStorageInterface - immediate error", myErr) );
  776.             }
  777.             break;
  778.             
  779.         case kNewInterfaceRef:
  780.             InitParamBlock(gStorageClassInfo.deviceRef, usbPB);
  781.             // Note: gStorageClassInfo.usbWIndex will be set to zero by InitParamBlock
  782.             // so set it again to gStorageClassInfo.interfaceIndex before calling USBNewInterfaceRef
  783.             usbPB->usbActCount =        0;
  784.             usbPB->usb.cntl.WIndex =            gStorageClassInfo.interfaceNumber;
  785.             usbPB->usbRefcon |=        kCompletionPending;
  786.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  787.  
  788.             myErr = USBNewInterfaceRef(usbPB);
  789.             if(ImmediateError(myErr))
  790.             {
  791.                 gConfigureStatus = kConfigureFailed;
  792.                 IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: kNewInterfaceRef - immediate error", myErr) );
  793.             }
  794.             break;
  795.                 
  796.         case kStorageConfigureInterface:
  797.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  798.  
  799.             usbPB->usbActCount =        0;
  800.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  801.             usbPB->usbRefcon |=        kCompletionPending;
  802.             
  803.             gStorageClassInfo.interfaceNumber =        0;            // Find First calls 'FindNextInterface' with WIndex = 0
  804.                                                                             // Find Next calls 'FindNextInterface' with WIndex = InterfaceNumber
  805.             
  806.             myErr = USBConfigureInterface(usbPB);
  807.             if (ImmediateError(myErr))
  808.             {
  809.                 gConfigureStatus = kConfigureFailed;
  810.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageConfigureInterface - immediate error", myErr) );
  811.             }
  812.             break;
  813.         
  814.         case kStorageFindInterruptPipe:
  815.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  816.  
  817.             usbPB->usbFlags =            kUSBIn;
  818.             usbPB->usbClassType =    kUSBInterrupt;
  819.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  820.             usbPB->usbRefcon |=        kCompletionPending;
  821.  
  822.             myErr = USBFindNextPipe( usbPB );
  823.             if (ImmediateError(myErr))
  824.             {
  825.                 gConfigureStatus = kConfigureFailed;
  826.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindInterruptPipe - immediate error", myErr) );
  827.                 usbPB->usbRefcon = kReturnFromDriver;
  828.             }
  829.             break;
  830.         
  831.         case kStorageFindBulkInPipe:
  832.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  833.  
  834.             usbPB->usbFlags =            kUSBIn;
  835.             usbPB->usbClassType =    kUSBBulk;
  836.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  837.             usbPB->usbRefcon |=        kCompletionPending;
  838.  
  839.             myErr = USBFindNextPipe( usbPB );
  840.             if (ImmediateError(myErr))
  841.             {
  842.                 gConfigureStatus = kConfigureFailed;
  843.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkInPipe - immediate error", myErr) );
  844.                 usbPB->usbRefcon = kReturnFromDriver;
  845.             }
  846.             break;
  847.         
  848.         case kStorageFindBulkOutPipe:
  849.             InitParamBlock(gStorageClassInfo.interfaceRef, usbPB);
  850.  
  851.             usbPB->usbFlags =            kUSBOut;
  852.             usbPB->usbClassType =    kUSBBulk;
  853.             usbPB->usbCompletion =    (USBCompletion)StorageDeviceConfigureCompletion;
  854.             usbPB->usbRefcon |=        kCompletionPending;
  855.  
  856.             myErr = USBFindNextPipe( usbPB );
  857.             if (ImmediateError(myErr))
  858.             {
  859.                 gConfigureStatus = kConfigureFailed;
  860.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageFindBulkOutPipe - immediate error", myErr) );
  861.                 usbPB->usbRefcon =    kReturnFromDriver;
  862.             }
  863.             break;
  864.         
  865.         case kStorageReadInterrupt:            
  866.             InitParamBlock(gStorageClassInfo.interruptPipeRef, usbPB);
  867.  
  868.             usbPB->usbBuffer =        (Ptr)gStorageClassInfo.interruptReport;
  869.             usbPB->usbReqCount =        0x02;
  870.             usbPB->usbCompletion =    (USBCompletion)ReadInterruptCompletion;
  871.             usbPB->usbRefcon |=        kCompletionPending;
  872.         
  873.             myErr = USBIntRead(usbPB);
  874.             if(ImmediateError(myErr))
  875.             {
  876.                 gConfigureStatus = kConfigureFailed;
  877.                 IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, kUSBInternalErr, "\pStorageClass: kStorageReadInterrupt - immediate error", myErr) );
  878.             }
  879.             break;
  880.             
  881.         case kReturnFromDriver:
  882.             break;
  883.             
  884.         default:
  885.             gConfigureStatus = kConfigureFailed;
  886.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Transaction initiated with bad refcon value", usbPB->usbRefcon) );
  887.             usbPB->usbRefcon = kUndefined + kReturnFromDriver;
  888.             break;
  889.     }
  890.     
  891. // At this point the control is returned to the system.  If a USB transaction
  892. // has been initiated, then it will call the Complete procs
  893. // (below) to handle the results of the transaction.
  894. }
  895.  
  896. static void
  897. StorageDeviceConfigureCompletion(USBPB *usbPB)
  898. {
  899. StorageClassTransactionPB*        pTransPB = (StorageClassTransactionPB*) usbPB;
  900. USBInterfaceDescriptorPtr        pInterfaceDescriptor;
  901. UInt32                                i;
  902.  
  903.     gStorageClassInfo.transDepth--;
  904.         
  905.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, StateStr(usbPB->usbRefcon, kPString) , 3 ) );
  906.     
  907.     if ((gStorageClassInfo.transDepth < 0) || (gStorageClassInfo.transDepth > 1))
  908.     {
  909.         gConfigureStatus = kConfigureFailed;
  910.         IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass - Illegal Transaction Depth", gStorageClassInfo.transDepth) );
  911.     }
  912.     
  913.     // We should only retry if the error is a USB transaction problem
  914.     // Device errors are handled outside of the state machine.
  915.     if ((usbPB->usbStatus != noErr) && (usbPB->usbStatus != kUSBPending))
  916.     {
  917.         IF_DEBUG( USBExpertStatus(usbPB->usbReference, "\pStorage Driver: Completion Error", usbPB->usbStatus) );
  918.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  919.         usbPB->usbRefcon |= kRetryTransaction;
  920.         gStorageClassInfo.retryCount--;
  921.         if (!gStorageClassInfo.retryCount)
  922.         {
  923.             gConfigureStatus = kConfigureFailed;
  924.             IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: Too many retries", usbPB->usbRefcon) );
  925.             usbPB->usbRefcon = kReturnFromDriver;
  926.             return;
  927.         }
  928.     }
  929.     else
  930.     {
  931.         usbPB->usbRefcon &= ~kRetryTransaction;
  932.         gStorageClassInfo.retryCount = kStorageRetryCount;
  933.     }
  934.  
  935.     if (usbPB->usbRefcon & kCompletionPending)             
  936.     {                                                
  937.         usbPB->usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  938.         switch(usbPB->usbRefcon)
  939.         {
  940.             case kGetFullConfiguration:
  941.                 usbPB->usbRefcon = kSetConfig;
  942.                 gStorageClassInfo.pFullConfigDescriptor = usbPB->usbBuffer;        // Save the config descriptor
  943.                 if (gStorageClassInfo.pFullConfigDescriptor == nil)
  944.                 {
  945.                     gConfigureStatus = kConfigureFailed;
  946.                     usbPB->usbRefcon = kReturnFromDriver;
  947.                     
  948.                     IF_DEBUG( USBExpertFatalError(usbPB->usbReference, kUSBInternalErr, "\pStorageClass: USBGetFullConfiguration - pointer is nil", usbPB->usbRefcon) );
  949.                 }
  950.                 break;
  951.                 
  952.             case kSetConfig:
  953.                 BlockCopy(    (void *) &gStorageClassInfo.pFullConfigDescriptor,
  954.                                 (void *) &gStorageClassInfo.partialConfigDescriptor,
  955.                                 (Size) (sizeof(USBConfigurationDescriptor) ) );
  956.                 
  957.                 for (i=0; i < gStorageClassInfo.partialConfigDescriptor.numInterfaces; i++)
  958.                 {
  959.                     gStorageClassInfo.interfaceRefArray[i] = 0;
  960.                     
  961.                     GetInterfaceDescriptor(    gStorageClassInfo.pFullConfigDescriptor,
  962.                                                     i,
  963.                                                     &pInterfaceDescriptor);
  964.                     BlockCopy(    (void *)pInterfaceDescriptor,
  965.                                     (void *)(&(gStorageClassInfo.interfaceDescriptors[i])),
  966.                                     (Size)(pInterfaceDescriptor->length));
  967.                 }
  968.                 
  969.                 gStorageClassInfo.pInterfaceDescriptor = &(gStorageClassInfo.interfaceDescriptors[0]);
  970.                 
  971.                 gStorageClassInfo.interfaceIndex =        0;
  972.                 gStorageClassInfo.interfaceCount =        gStorageClassInfo.partialConfigDescriptor.numInterfaces;
  973.                 usbPB->usbRefcon =                            kFindStorageInterface;
  974.                 break;
  975.                 
  976.             case kFindStorageInterface:
  977.                 gStorageClassInfo.interfaceNumber =        usbPB->usb.cntl.WIndex;
  978.                 usbPB->usbRefcon =                            kNewInterfaceRef;
  979.                 break;
  980.                 
  981.             case kNewInterfaceRef:
  982.                 gStorageClassInfo.interfaceRef =        usbPB->usbReference;
  983.                 usbPB->usbRefcon =                        kStorageConfigureInterface;
  984.                 break;
  985.                 
  986.             case kStorageConfigureInterface:
  987.                 usbPB->usbRefcon = kStorageFindInterruptPipe;
  988.                 break;
  989.             
  990.             case kStorageFindInterruptPipe:                                
  991.                 gStorageClassInfo.interruptPipeRef =     usbPB->usbReference;
  992.                 usbPB->usbRefcon =                            kStorageFindBulkInPipe;
  993.                 break;
  994.                 
  995.             case kStorageFindBulkInPipe:
  996.                 gStorageClassInfo.readPipeRef =     usbPB->usbReference;
  997.                 usbPB->usbRefcon =                    kStorageFindBulkOutPipe;
  998.                 break;
  999.             
  1000.             case kStorageFindBulkOutPipe:
  1001.                 gStorageClassInfo.writePipeRef = usbPB->usbReference;
  1002.                 gConfigured = true;                                // Set the configured flag so we can respond to calls via the dispatch table
  1003.                 gConfigureStatus = kConfigureComplete;        // Flag for client to determine that we are no configured
  1004.                 IF_DEBUG(USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: Driver Configured.", 3 ) );            
  1005.                 usbPB->usbRefcon = kReturnFromDriver;
  1006.                 break;
  1007.             
  1008.             case kStorageReadInterrupt:    
  1009.     //            ProcessStorageInterrupt(pStoragePB);
  1010.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 0:", gStorageClassInfo.interruptReport[0] ));
  1011.                 IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClass: kStorageReadInterrupt. Byte 1:", gStorageClassInfo.interruptReport[1] ));
  1012.                 
  1013.                 usbPB->usbRefcon = kStorageReadInterrupt;
  1014.                 break;
  1015.     
  1016.             case kNilCompletion:
  1017.             default:
  1018.                 if ( usbPB->usbStatus == noErr )
  1019.                     usbPB->usbRefcon = kUndefined | kReturnFromDriver;
  1020.                 break;
  1021.         }
  1022.     }
  1023.     
  1024.     if ( usbPB->usbStatus == noErr )
  1025.     {
  1026.         if (!(usbPB->usbRefcon & kReturnFromDriver))
  1027.             StorageDeviceInitiateConfiguration(usbPB);
  1028.     }
  1029.     else
  1030.     {
  1031.         gConfigureStatus = kConfigureFailed;
  1032.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, StateStr(usbPB->usbRefcon, kPString), usbPB->usbRefcon) );
  1033.         IF_DEBUG( USBExpertFatalError(gStorageClassInfo.deviceRef, usbPB->usbStatus, USBStatusStr(usbPB->usbStatus, kPString), 0) );
  1034.     }
  1035. }
  1036.  
  1037.  
  1038. void 
  1039. StorageDriverEntry(    USBDeviceRef                    deviceRef,
  1040.                             USBDeviceDescriptorPtr        deviceDescriptorPtr,
  1041.                             USBInterfaceDescriptorPtr    pInterfaceDescriptor)
  1042. {
  1043.     UInt32    usbVersion;
  1044.             
  1045.     IF_DEBUG( USBExpertStatus(deviceRef, "\pStorage Driver Entry" , 1 ) );
  1046.     
  1047.     if( !gBeenThereDoneThat)
  1048.     {
  1049.         gBeenThereDoneThat = true;
  1050.         
  1051.         // Check for the correct version of the USB manager.
  1052.         // We are ok with all version later than 1.0
  1053.         
  1054.         if (GetUSBVersion(&usbVersion) == noErr)
  1055.         {
  1056.             if ((usbVersion & 0xffff0000) < 0x01010000)        // Wrong USB version number so do NOT continue
  1057.             {
  1058.                 IF_DEBUG( USBExpertStatus(deviceRef, "\pWrong version of the USB Manager" , 1 ) );
  1059.                                 
  1060.                 IF_DEBUG( USBExpertFatalError(deviceRef, 0, "\pWrong USB Manager version" , 0) );
  1061.                 gConfigured = false;                                // Set the configured flag so we can respond to calls via the dispatch table
  1062.                 gConfigureStatus = kConfigureFailed;        // Flag for client to determine that configuration failed
  1063.                 
  1064.                 return ;
  1065.             }
  1066.         }
  1067.         
  1068.         // Initialize the global data structures
  1069.         BlockZero(&gStorageClassInfo, sizeof(StorageClassInfo));
  1070.         BlockZero(&gInterruptPB, sizeof(StorageClassTransactionPB));
  1071.         BlockZero(&gCommandPB, sizeof(StorageClassTransactionPB));
  1072.         
  1073.         gStorageClassInfo.retryCount =                kStorageRetryCount;
  1074.         gStorageClassInfo.deviceDescriptor =        *deviceDescriptorPtr;        // keep a copy of the device descriptor
  1075.         gStorageClassInfo.pInterfaceDescriptor =    pInterfaceDescriptor;
  1076.         gStorageClassInfo.deviceRef =                    deviceRef;
  1077.         gStorageClassInfo.interfaceRef =                deviceRef;
  1078.         gStorageClassInfo.transDepth =                0;                                    // init Delay Callback Depth
  1079.  
  1080.         InitParamBlock( deviceRef, &gStorageClassInfo.usbPB );
  1081.                 
  1082.         //    Start out at first state
  1083.         if (gStorageClassInfo.pInterfaceDescriptor != NULL)
  1084.         {
  1085.             gStorageClassInfo.usbPB.usbRefcon = kStorageConfigureInterface;
  1086.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as interface driver" , 0 ) );
  1087.         }
  1088.         else
  1089.         {
  1090.             gStorageClassInfo.usbPB.usbRefcon = kGetFullConfiguration;
  1091.             IF_DEBUG( USBExpertStatus(deviceRef, "\pStart as device driver" , 0 ) );
  1092.         }
  1093.         
  1094.         gConfigureStatus = kConfigureInProgress;
  1095.         StorageDeviceInitiateConfiguration(&gStorageClassInfo.usbPB);
  1096.     }
  1097. }
  1098.  
  1099.  
  1100. void
  1101. StorageClassDriverFinalize( void )
  1102. {
  1103. OSStatus    status;
  1104.  
  1105.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverFinalize." , 0 ) );
  1106.     
  1107.     //
  1108.     // Make sure all pipes are finished with transactions by calling the USBAbortPipeByReference function
  1109.     //
  1110.     status = USBAbortPipeByReference(gStorageClassInfo.deviceRef);                // Control pipe
  1111.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Control pipe" , status ) );
  1112.     
  1113.     status = USBAbortPipeByReference(gStorageClassInfo.interruptPipeRef);    // Interrupt pipe
  1114.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Interrupt pipe" , status ) );
  1115.     
  1116.     status = USBAbortPipeByReference(gStorageClassInfo.readPipeRef);            // Read pipe
  1117.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Read pipe" , status ) );
  1118.     
  1119.     status = USBAbortPipeByReference(gStorageClassInfo.writePipeRef);            // Write pipe
  1120.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pUSBAbortPipeByReference: Write pipe" , status ) );
  1121. }
  1122.  
  1123.  
  1124. OSStatus    
  1125. StorageClassDriverNotifyProc(UInt32    notification, void* pointer)
  1126. {
  1127. #pragma unused (notification, pointer)
  1128. OSStatus status = noErr;
  1129.         
  1130.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gConfigureStatus: " , gConfigureStatus ) );
  1131.     IF_DEBUG( USBExpertStatus(gStorageClassInfo.deviceRef, "\pStorageClassDriverNotifyProc. gOKToRemoval: " , gOKToRemoval ) );
  1132.     
  1133.     // Don't allow removal if we are busy configuration the interface.
  1134.     if (gConfigureStatus == kConfigureInProgress)
  1135.     {
  1136.         status = kUSBDeviceBusy;
  1137.     }
  1138.     
  1139.     // Don't allow removal until the Shim says it's ok
  1140.     if (gOKToRemoval == false)
  1141.     {
  1142.         status = kUSBDeviceBusy;
  1143.     }
  1144.     
  1145.     return (status);
  1146. }
  1147.